// 抽象组件：咖啡
interface Coffee {
    getDescription(): string;
    getPrice(): number;
}

// 具体组件：普通咖啡
class SimpleCoffee implements Coffee {
    getDescription(): string {
        return "Simple coffee";
    }

    getPrice(): number {
        return 5;
    }
}

// 抽象装饰者：咖啡装饰器
abstract class CoffeeDecorator implements Coffee {
    protected coffee: Coffee;

    constructor(coffee: Coffee) {
        this.coffee = coffee;
    }

    getDescription(): string {
        return this.coffee.getDescription();
    }

    getPrice(): number {
        return this.coffee.getPrice();
    }
}

// 具体装饰者：牛奶装饰器
class MilkDecorator extends CoffeeDecorator {
    constructor(coffee: Coffee) {
        super(coffee);
    }

    getDescription(): string {
        return this.coffee.getDescription() + ", with milk";
    }

    getPrice(): number {
        return this.coffee.getPrice() + 2;
    }
}

// 具体装饰者：糖浆装饰器
class SyrupDecorator extends CoffeeDecorator {
    constructor(coffee: Coffee) {
        super(coffee);
    }

    getDescription(): string {
        return this.coffee.getDescription() + ", with syrup";
    }

    getPrice(): number {
        return this.coffee.getPrice() + 3;
    }
}

// 具体装饰者：巧克力装饰器
class ChocolateDecorator extends CoffeeDecorator {
    constructor(coffee: Coffee) {
        super(coffee);
    }

    getDescription(): string {
        return this.coffee.getDescription() + ", with chocolate";
    }

    getPrice(): number {
        return this.coffee.getPrice() + 4;
    }
}

// 客户端代码
// @ts-ignore
function clientCode(coffee: Coffee) {
    console.log("Description:", coffee.getDescription());
    console.log("Price:", coffee.getPrice());
    console.log();
}

// 使用装饰设计模式为咖啡添加配料
const simpleCoffee = new SimpleCoffee();
clientCode(simpleCoffee);

const coffeeWithMilk = new MilkDecorator(simpleCoffee);
clientCode(coffeeWithMilk);

const coffeeWithSyrup = new SyrupDecorator(simpleCoffee);
clientCode(coffeeWithSyrup);

const coffeeWithChocolate = new ChocolateDecorator(simpleCoffee);
clientCode(coffeeWithChocolate);

const coffeeWithMilkAndSyrup = new SyrupDecorator(new MilkDecorator(simpleCoffee));
clientCode(coffeeWithMilkAndSyrup);
